package com.power.sifa.supervise.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson2.JSON;
import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
import com.ding.api.Di_userFeign;
import com.ding.dto.Di_messageDto;
import com.ding.dto.Di_todoDto;
import com.ding.dto.Di_userDto;
import com.ding.model.enumeration.St_pStatus;
import com.plf.common.domain.ResponseDTO;
import com.plf.common.domain.YesNo;
import com.plf.common.exception.BusinessException;
import com.plf.core.base.model.Ha_user;
import com.plf.core.base.service.Ha_attachmentService;
import com.plf.core.base.service.Ha_userService;
import com.power.flowable.api.IPersonalFeign;
import com.power.sifa.approve.dao.Apl_attachmentDao;
import com.power.sifa.approve.executor.AdmreExecutor;
import com.power.sifa.approve.model.*;
import com.power.sifa.approve.model.enumeration.*;
import com.power.sifa.approve.service.*;
import com.power.sifa.base.model.Apl_common_notice;
import com.power.sifa.base.model.enumeration.Tp_noticemsg;
import com.power.sifa.base.service.Apl_common_noticeService;
import com.power.sifa.net.model.ProcessInfo;
import com.power.sifa.net.model.enumeration.Tp_matter;
import com.power.sifa.supervise.dao.Apl_superviseDao;
import com.power.sifa.supervise.model.Apl_supervise;
import com.power.sifa.supervise.service.Apl_superviseService;
import com.power.sifa.supervise.service.BusinessSuperviseService;
import com.power.sifa.util.VerifyCodeUtil;
import com.power.sifa.util.service.impl.DidiSmsServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class BusinessSuperviseServiceImpl extends AdmreExecutor implements BusinessSuperviseService {


    /**
     * 申请材料附件生成路径
     */
    @Value("${power.file-path:#{null}}")
    private String filePath;

    /**
     * 短信地址
     */
    @Value("${sms.path: #{null}}")
    public String path;


    @Value("${sfding.url: #{null}}")
    public String sfdingUrl;

    /**
     * 赣政通复议监督处理页面的applyid
     * /pages/supervise/middle?id=111&applyid=222
     */
    public final String sfdingPath = "/pages/supervise/middle?id=${0}&applyid=${1}";


    /**
     * 受理科室电话号码
     */
    public final String acceptPhone = "0791-83884349";
    /**
     * 审理科室的电话号码
     */
    public final String hearPhone = "0791-83884740";


    @Autowired
    private Apl_superviseDao dao;

    @Autowired
    private Ha_attachmentService ha_attachmentService;

    @Resource
    private Apl_targetService apl_targetService;

    @Resource
    private Apl_arrive_detailService apl_arrive_detailService;

    @Resource
    private Apl_arrive_personService apl_arrive_personService;

    @Resource
    private Apl_arrive_materialService apl_arrive_materialService;

    @Resource
    private BusinessApproveService businessApproveService;

    @Resource
    private Apl_arrive_receiptService apl_arrive_receiptService;

    @Resource
    private Apl_attachmentDao apl_attachmentDao;

    @Resource
    private Ha_userService ha_userService;

    @Resource
    private Di_userFeign diUserFeign;

    @Resource
    private com.ding.service.Di_todoRemoteService di_todoRemoteService;

    @Resource
    private IPersonalFeign iPersonalFeign;
    @Resource
    private Apl_mainService apl_mainService;
    @Resource
    private Apl_admre_auditService apl_admre_auditService;
    @Resource
    private Apl_superviseService apl_superviseService;

    @Resource
    private Apl_applicantService apl_applicantService;

    @Resource
    private Aprv_process_materialsService aprv_process_materialsService;

    @Resource
    private Apl_common_noticeService apl_common_noticeService;



    @Override
    public Map<String, String> startBusinessProced(String applyid, String proctype, String userid, Map<String, Object> docfield) throws Exception {
        Map<String, String> result;
        Tp_proctypeEnum proctypeEnum = Tp_proctypeEnum.getByKey(proctype);
        result = this.superviseBusiness(applyid, proctypeEnum, userid, docfield);
        return result;
    }

    /**
     * 受理子流程业务操作
     *
     * @param applyid
     * @param proctypeEnum
     * @param userid
     * @return
     * @throws ParseException
     * @throws BusinessException
     */
    private Map<String, String> superviseBusiness(String applyid, Tp_proctypeEnum proctypeEnum, String userid, Map<String, Object> docfield) throws ParseException, BusinessException {
        Apl_supervise supObj = this.apl_superviseService.getById(applyid);
        Apl_main faMainObj = this.apl_mainService.getById(applyid);
        Apl_main mainObj = this.apl_mainService.createMain(userid, proctypeEnum.getProcesskey(), faMainObj, Tp_matter.PUB_SUPERVISE);

        // 校验父流程是否挂起
        ResponseDTO isSupRes = this.iPersonalFeign.isSuspended(faMainObj.getInstid());
        if (0 != isSupRes.getCode()) {
            throw new RuntimeException("查询父流程是否挂起失败");
        }
        Boolean isSup = (Boolean) isSupRes.getData();
        if (isSup) {
            throw new RuntimeException("已存在其他的子流程");
        }
        // 子流程状态
        Integer statusapply = proctypeEnum.getStatus();

        // 1. 启动一个子流程
        String processinstanceid = this.createSonProcess(faMainObj, mainObj, supObj, userid, statusapply, proctypeEnum.getId());
        // 2. 挂起父流程
        try {
            ResponseDTO res = this.iPersonalFeign.suspendProcess(faMainObj.getInstid());
            if (0 != res.getCode()) {
                throw new RuntimeException(res.getMsg());
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("superviseBusiness 挂起父流程失败->  msg[{}]", e.getMessage());
        }

        // 3. 查询子流程的taskid前端自动跳转
        ResponseDTO resTask = this.iPersonalFeign.queryTaskidByInstid(processinstanceid);
        log.info("superviseBusiness 执行成功 -> 子流程: {}", processinstanceid);
        Map<String, String> result = new HashMap<>(16);
        result.put("processinstanceid", processinstanceid);
        if (0 == resTask.getCode()) {
            String newTaksid = (String) resTask.getData();
            result.put("taskid", newTaksid);
        }
        // 4.保存决定类型和是否需要整改字段
        if (ObjectUtil.isNotNull(docfield)) {
            if (docfield.containsKey("decisiontype")) {
                Integer decisiontype = Integer.valueOf(docfield.get("decisiontype").toString());
                if (ObjectUtil.isNotNull(decisiontype)) {
                    supObj.setDecisiontype(decisiontype);
                }
            }
            if (docfield.containsKey("isrectifica")) {
                Integer isrectifica = Integer.valueOf(docfield.get("isrectifica").toString());
                if (ObjectUtil.isNotNull(isrectifica)) {
                    supObj.setIsrectifica(isrectifica);
                }
            }
            // 保存对应的状态
            this.apl_superviseService.saveOrUpdate(supObj);
        }
        return result;
    }

    /**
     * 创建保存一个子流程
     *
     * @param faMainObj
     * @param mainObj
     * @param supObj
     * @param userid
     * @param status
     * @param procType
     * @return
     * @throws BusinessException
     * @throws ParseException
     */
    private String createSonProcess(Apl_main faMainObj, Apl_main mainObj, Apl_supervise supObj, String userid, Integer status, Integer procType) throws ParseException, BusinessException {
        // 1. 启动一个子流程
        ResponseDTO res = this.iPersonalFeign.startSonProcess(faMainObj.getInstid(), mainObj.getId(), userid, mainObj.getFormid(), null, new HashMap<>(16));
        if (0 != res.getCode()) {
            log.error("startBusinessProced 启动子流程失败 -> msg[{}]", res.getMsg());
            throw new BusinessException(res.getMsg());
        }
        ProcessInfo processObj = JSON.parseObject(JSON.toJSONString(res.getData()), ProcessInfo.class);
        mainObj.setInstid(processObj.getProcessinstanceid());
        mainObj.setScatid(processObj.getScatid());
        mainObj.setAcceptcode(faMainObj.getAcceptcode());
        this.apl_mainService.saveOrUpdate(mainObj);

        // 2. 通过父流程applyid, 查询生成子流程业务表数据
        Apl_admre_audit auditObj = new Apl_admre_audit();
        auditObj.setId(mainObj.getId());
        auditObj.setType(procType);
        auditObj.setCode(faMainObj.getAcceptcode());
        auditObj.setApplyid(faMainObj.getId());
        auditObj.setReason(supObj.getFacbasis());
        auditObj.setApplyname(supObj.getApplyname());
        auditObj.setTargetname(supObj.getTargetname());
        auditObj.setIsdelay(YesNo.NO);
        // 提交日期为收到日期
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat formatT = new SimpleDateFormat("yyyy年M月d日");
        auditObj.setReceiptdate(formatT.format(format.parse(faMainObj.getSubtime())));
        auditObj.setAdmrequest(supObj.getMatinfo());
        auditObj.setAcceptfirstid(supObj.getFirstid());
        auditObj.setAcceptfirstname(supObj.getFirstname());
        auditObj.setAcceptsecondid(supObj.getSecondid());
        auditObj.setAcceptsecondname(supObj.getSecondname());
        auditObj.setHearfirstid(supObj.getFirstid());
        auditObj.setHearfirstname(supObj.getFirstname());
        auditObj.setHearsecondid(supObj.getSecondid());
        auditObj.setHearsecondname(supObj.getSecondname());
        auditObj.setAssistantid(supObj.getThirdid());
        auditObj.setAssistantname(supObj.getThirdname());
        // 第三人信息
        auditObj.setThirdper(super.queryThirdper(faMainObj.getId()));
        // 行政复议审批表类型状态
        auditObj.setStatus(status);
        this.apl_admre_auditService.saveOrUpdate(auditObj);
        return processObj.getProcessinstanceid();
    }



    @Override
    public void sendApplicantMessage(String applyid, String userid) {
        Apl_supervise apl_supervise = this.apl_superviseService.getById(applyid);
        Apl_main apl_main = apl_mainService.getById(applyid);
        List<Apl_attachment> attachments = this.apl_attachmentDao.queryList(applyid);
        // 查询当前applyid的申请人
        List<Apl_applicant> applicantList = this.apl_applicantService.getApplicantByApplyid(applyid);
        if (CollUtil.isNotEmpty(applicantList) && ObjectUtils.isNotEmpty(apl_supervise) && ObjectUtil.isNotNull(apl_main)) {
            // 查询对应的材料
            List<Aprv_process_materials> materials = aprv_process_materialsService.getAllMaterialByApplyId(applyid);

            if (CollUtil.isNotEmpty(materials)) {
                // 找到材料类型为复议监督告知书的文件的盖章文件
                materials = materials.stream().filter(el -> el.getMattype().equals(Tp_procmaterial.SUPERVISE_TELL)).filter(el -> el.getSign().equals(Tp_sign.SIGNED)).collect(Collectors.toList());
            }
            if  (CollUtil.isNotEmpty(materials)) {
                // 生成送达记录
                Apl_arrive_detail detail = Apl_arrive_detail.builder().id(NanoIdUtils.randomNanoId()).acceptcode(apl_main.getAcceptcode())
                        .applyid(applyid).createtime(new Date()).customer(YesNo.NO).build();
                // 生成送达人员
                List<Apl_arrive_person> apl_arrive_personList = new ArrayList<>();
                applicantList.stream().forEach(el -> {
                    Apl_arrive_person apl_arrive_person = Apl_arrive_person.builder().id(NanoIdUtils.randomNanoId()).recordid(detail.getId())
                            .address(el.getAddr()).phone(el.getTel()).recipient(el.getName()).sendway(Tp_sendway.ELEC)
                            .sendstatus(St_arrive.SENDING).sendtime(new Date()).build();
                    apl_arrive_personList.add(apl_arrive_person);
                });
                // 生成送达材料
                List<Apl_arrive_material> apl_arrive_materialList = new ArrayList<>();
                materials.forEach(el -> {
                    Apl_arrive_material apl_arrive_material = Apl_arrive_material.builder().id(NanoIdUtils.randomNanoId()).recordid(detail.getId())
                            .attachid(el.getAttachid()).matttype(el.getMattype()).materialid(el.getId()).build();
                    apl_arrive_materialList.add(apl_arrive_material);
                });
                this.apl_arrive_detailService.saveOrUpdate(detail);
                this.apl_arrive_personService.saveAll(apl_arrive_personList);
                this.apl_arrive_materialService.saveAll(apl_arrive_materialList);
                // 发送送达短信
                final String acceptcode = apl_main.getAcceptcode();
                final String phone = acceptPhone + '，' + hearPhone;
                if (CollUtil.isNotEmpty(applicantList) && CollUtil.isNotEmpty(materials)) {
                    applicantList.forEach(applicant -> {
                        // 生成验证码
                        final String code = VerifyCodeUtil.getVerify();
                        // 生成送达回执id
                        String receiptid = applyid + NanoIdUtils.randomNanoId();
                        // 短信内容访问的前端地址
                        DidiSmsServiceImpl bean = new DidiSmsServiceImpl();
                        // 对应的参数进行设置 对应的字段为用户名称，案号,文件类型，验证码，电话
                        List<String> params = new ArrayList<>();
                        // 送达人
                        params.add(applicant.getName());
                        // 案号
                        params.add(acceptcode);
                        // 材料名称
                        params.add("行政复议监督通知书");

                        // 签收网址
                        params.add(this.path);
                        // 验证码
                        params.add(code);
                        // 电话
                        params.add(phone);
                        bean.sendTemplate(DidiSmsServiceImpl.tpl_fileaccept, params, applicant.getTel());

                        // 2. 存储一条电子送达回执记录
                        // 过期时间为当前的时间加7天工作日
                        Date expiredTime = businessApproveService.getTargetDay(new Date(), 7);
                        Apl_arrive_receipt receiptObj = Apl_arrive_receipt.builder().id(receiptid).applyid(applyid)
                                .code(acceptcode).verifycode(code).recordid(detail.getId()).sendtime(new Date()).expiredtime(expiredTime)
                                .status(St_receipt.TODELIVER).build();

                        this.apl_arrive_receiptService.saveOrUpdate(receiptObj);
                    });
                }
                String content = "复议监督案件（" + apl_main.getAcceptcode() + "）成功发送通知书送达短信给申请人";
                this.createSupervseNotice(userid,content, Tp_noticemsg.SUPERVISE_ARRIVE);
            }
        }
    }


    /**
     * 复议监督消息通知生成
     */
    private void createSupervseNotice(String userid, String content,Integer msgType) {
        Apl_common_notice notice = Apl_common_notice.builder().id(NanoIdUtils.randomNanoId())
                .createtime(new Date()).warntime(new Date()).userid(userid).content(content).msgtype(msgType)
                .router(null).build();
        this.apl_common_noticeService.sendMessage(notice);
    }

    @Override
    public void sendDiTodo(String applyid, String userId, List<String> phones, boolean isDecision) {
        Apl_main apl_main = apl_mainService.getById(applyid);
        Apl_supervise apl_supervise = this.apl_superviseService.getById(applyid);
        List<String> diTodoIds = new ArrayList<>();
        // 查询当前applyid的被申请人
        List<Apl_target> targetList = this.apl_targetService.getTargetListByApplyidAndPhone(applyid, phones);
        // 查询当前的系统承办人的信息
        Ha_user haUser = ha_userService.getById(userId);
        if (CollectionUtil.isNotEmpty(targetList) && ObjectUtil.isNotNull(haUser)) {
            phones.add(haUser.getMobile());
            phones = phones.stream().filter(StringUtils::isNotEmpty).collect(Collectors.toList());
            ResponseDTO userResponseDTO = diUserFeign.getUserByPhones(phones);
            if (userResponseDTO.getCode() == 0 && ObjectUtil.isNotNull(userResponseDTO.getData())) {
                // 查询对应的用户
                List<Di_userDto> diUserList = JSONArray.parseArray(JSON.toJSONString(userResponseDTO.getData()), Di_userDto.class);
                if (CollUtil.isNotEmpty(diUserList)) {
                    Di_userDto sendUser = diUserList.stream().filter(el -> el.getMobile().equals(haUser.getMobile())).findAny().orElse(null);
                    if (ObjectUtil.isNull(sendUser)) {
                        log.error("未找到发送用户信息 -> mobile: {}", haUser.getMobile());
                        return;
                    }
                    List<Di_userDto> receiveUserList = diUserList.stream().filter(el -> !el.getMobile().equals(haUser.getMobile())).collect(Collectors.toList());
                    // 限制数量小于10
                    if (CollectionUtil.isNotEmpty(receiveUserList) && receiveUserList.size() < 10 && ObjectUtil.isNotNull(sendUser)) {
                        // 发送对应消息到赣政通
                        String title = "南昌司法复议监督：被申请人待处理";
                        SimpleDateFormat format = new SimpleDateFormat("yyyy年M月d日");
                        final String targetName = String.join("，", targetList.stream().map(Apl_target::getName).collect(Collectors.toList()));
                        String content = "";
                        if (!isDecision) {
                            // 非决定环节
                            content = targetName + "政府，市政府收到申请人对你府的行政复议监督申请（" + apl_main.getAcceptcode()  + ")，要求你府于60日内反馈处理情况，现期限将近，请抓紧时间履行。";
                        } else {
                            content = targetName + "政府，市政府于" + format.format(new Date()) + "下达【行政复议监督通知书】（" + apl_main.getAcceptcode()  + ")，要求你府于60日内反馈处理情况，现期限将近，请抓紧时间履行。";
                        }
                        if (isDecision) {
                            for (Di_userDto diUser : receiveUserList) {
                                // 查询当前的被申请人
                                String diId = NanoIdUtils.randomNanoId();
                                String routeUrl = sfdingPath.replace("${0}", diId).replace("${1}", applyid);
                                Di_todoDto todoDto = new Di_todoDto().builder().id(diId)
                                        .bt(title).content(content).wh(apl_main.getAcceptcode()).moduleName("行政复议监督").action("被申请人处理").urgent("0").important("1")
                                        .sendUserId(sendUser.getId()).sendUserName(sendUser.getUserName()).sendDeptId(sendUser.getUnitId()).sendDeptName("南昌司法局")
                                        .receiveUserId(diUser.getId()).receiveUserName(diUser.getUserName())
                                        .receiveDeptId(diUser.getUnitId()).receiveDeptName(CollUtil.isNotEmpty(diUser.getDeptList()) ? diUser.getDeptList().get(0).getFullName() : "暂无")
                                        .sendTime(new Date()).url(sfdingUrl + "?todoid=" + diId).applyid(apl_main.getId()).pStatus(St_pStatus.PENDING)
                                        .route(routeUrl).build();

                                //                            diTodoIds.add(diId);
                                //                            ResponseDTO res = di_todoFeign.sendToDo(todoDto);
                                //                            if(0 != res.getCode()) {
                                //                                log.error("赣政通待办任务发送失败 -> {}", JSON.toJSONString(todoDto));
                                //                            } else {
                                //                                log.info("赣政通发送被复议监督被申请人待办成功 -> {},{}", applyid, diUser.getUserName());
                                //                            }

                                this.di_todoRemoteService.afterValidateSendToDo(todoDto);
                                diTodoIds.add(diId);
                                log.info("赣政通发送被复议监督被申请人待办成功 -> {},{}", applyid, diUser.getUserName());
                            }
                        } else {
                            for (Di_userDto diUser : receiveUserList) {
                                // 查询当前的被申请人
                                String diId = NanoIdUtils.randomNanoId();
//                                String routeUrl = sfdingPath.replace("${0}", diId).replace("${1}", applyid);

                                Di_messageDto messageDto = new Di_messageDto().builder().id(diId)
                                         .content(content).sendUserId(sendUser.getId()).sendUserName(sendUser.getUserName())
                                        .receiveUserId(diUser.getId()).receiveUserName(diUser.getUserName()).remindType(3)
                                        .actUrl(sfdingUrl + "?todoid=" + diId)
                                        .sendTime(new Date()).build();

                                this.di_todoRemoteService.afterValidateSendMessage(messageDto);
                                diTodoIds.add(diId);
                                log.info("赣政通发送被复议监督被申请人通知成功 -> {},{}", applyid, diUser.getUserName());
                            }
                        }
                    } else {
                        log.error("赣政通发送被复议监督被申请人待办失败,赣政通查询发送人和接收人信息为空-> {}", applyid);
                    }
                    if (ObjectUtil.isNotNull(apl_supervise) && CollUtil.isNotEmpty(diTodoIds)) {
                        if (isDecision) {
                            // 保存决定环节的待办id
                            String rectifitodoid = apl_supervise.getRectifitodoid();
                            if (StringUtils.isNotEmpty(rectifitodoid)) {
                                diTodoIds.addAll(new ArrayList<>(Arrays.asList(rectifitodoid.split(","))));
                            }
                            diTodoIds = diTodoIds.stream().distinct().collect(Collectors.toList());
                            apl_supervise.setRectifitodoid(String.join(",", diTodoIds));
                            this.apl_superviseService.saveOrUpdate(apl_supervise);
                        }
//                        else {
//                            // 保存审查环节的代办的id
//                            String reviewtodoid = apl_supervise.getReviewtodoid();
//                            if (StringUtils.isNotEmpty(reviewtodoid)) {
//                                diTodoIds.addAll(new ArrayList<>(Arrays.asList(reviewtodoid.split(","))));
//                            }
//                            diTodoIds = diTodoIds.stream().distinct().collect(Collectors.toList());
//                            apl_supervise.setReviewtodoid(String.join(",", diTodoIds));
//                            this.apl_superviseService.saveOrUpdate(apl_supervise);
//                        }
                    }
                }
            } else {
                log.error("赣政通发送被复议监督被申请人待办失败,获取赣政通用户信息失败 -> {}", applyid);
                log.error("赣政通发送被复议监督被申请人待办失败,查询接口报错 -> {}", userResponseDTO.getMsg());
            }
        }
    }

}
